use async_std::net::{TcpListener,Shutdown, TcpStream};
use async_std::prelude::*;
use async_std::task;
use async_std::sync::{Arc};
//use std::sync::Arc;
use std::collections::HashMap;
use std::io::Result;
use super::router::{Router};
use super::response::HttpState;
use super::request::{Request, HttpParam};
use super::response::Response;
async fn handle_request(server:Arc<Server>,clinet:TcpStream) -> Result<()>{
    let (reader, writer) = &mut (&clinet, &clinet);
    let mut buf: Vec<u8> = vec![0; 1024];
    reader.read(&mut buf).await.unwrap();
    let text: std::borrow::Cow<'_, str> = String::from_utf8_lossy(&buf);
    let request = Request::new(text.to_string(),reader);
    let response = Response::new(HttpState::OK,writer);
    if let Some(router) = request.get(HttpParam::ROUTER){
        if let Some(router) = server.routers.get(router.as_str()){
            (router.callback)(request,response);
        }
    }
    let _ =reader.shutdown(Shutdown::Both);
    Ok(())
}
pub struct Server{
    ip_port:String,
    routers:HashMap<&'static str,Router<Box<dyn Fn(Request,Response) + Send +Sync>>>
}
impl Server{
    pub fn new(ip:&'static str,port:i32)->Self{
        Server{
            ip_port:format!("{}:{}",ip,port),
            routers:HashMap::new()
        }
    }
    pub fn add_route<F>(mut self,path:&'static str, f:Box<dyn Fn(Request,Response) + Send +Sync>)-> Self{
            let router: Router<Box<dyn Fn(Request, Response) + Send +Sync>> = Router::new(path,f);
            self.routers.insert(path,router);
            self
    }
    pub fn run(self){
        task::block_on(async {
            let listener = TcpListener::bind(&self.ip_port).await.expect("bind error");
            let mut incoming = listener.incoming();
            let shared_server = Arc::new(self);
            while let Some(stream) = incoming.next().await {
                println!("用户链接");
                let stream: TcpStream = stream.expect("stream error");
                let server_temp =  shared_server.clone();
                task::spawn(handle_request(server_temp,stream));
            }
        });
    }
}